---
title: Промежуточное ПО
description: Узнайте, как использовать промежуточное ПО в Astro.
i18nReady: true
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';

**Промежуточное ПО**(Middleware) позволяет перехватывать запросы и ответы и динамически внедрять дополнительное поведение каждый раз, когда страница или эндпоинт должны быть отрендерены. Этот рендеринг происходит во время сборки для всех предварительно отрендеренных страниц, а для страниц, отрисовываемых по требованию, - при запросе маршрута.

Промежуточное ПО также позволяет устанавливать и передавать специфическую для запроса информацию между эндпоинтами и страницами, изменяя объект `locals`, который доступен во всех компонентах Astro и API эндпоинтах. Этот объект доступен даже при запуске этого промежуточного ПО во время сборки.

## Базовое использование

1. Создайте `src/middleware.js|ts` (В качестве альтернативы можно создать `src/middleware/index.js|ts`).

2. Внутри этого файла экспортируйте функцию [`onRequest()`](/ru/reference/api-reference/#onrequest), которой можно передать объект [`context`](#объект-context) и функцию `next()`. Это не должен быть экспорт по умолчанию.

    ```js title="src/middleware.js"
    export function onRequest ({ locals, request }, next) {
        // перехват данных из запроса
        // по желанию, измените свойства в `locals`
        locals.title = "New title";

        // верните ответ или результат вызова `next()`
        return next();
    };
    ```

3. В любом файле `.astro` получите данные ответа, используя `Astro.locals`.

    ```astro title="src/components/Component.astro"
    ---
    const data = Astro.locals;
    ---
    <h1>{data.title}</h1>
    <p>This {data.property} is from middleware.</p>
    ```

### Объект `context`

Объект [`context`](/ru/reference/api-reference/#контекст-конечной-точки) содержит информацию, которая будет доступна другому промежуточному ПО, маршрутам API и маршрутам `.astro` в процессе рендеринга.

Это необязательный аргумент, передаваемый в `onRequest()`, который может содержать объект `locals`, а также любые дополнительные свойства, которые будут переданы во время рендеринга. Например, объект `context` может содержать куки, используемые при аутентификации.

### Хранение данных в `context.locals`

`context.locals` - это объект, которым можно манипулировать внутри промежуточного ПО.

Этот объект `locals` передается в процессе обработки запроса и доступен в качестве свойства для [`APIContext`](/ru/reference/api-reference/#contextlocals) и [`AstroGlobal`](/ru/reference/api-reference/#astrolocals). Это позволяет обмениваться данными между промежуточным ПО, маршрутами API и страницами `.astro`. Это полезно для хранения специфических данных запроса, таких как данные пользователя, на всех этапах рендеринга.

:::tip[Свойства интеграции]
[Интеграции](/ru/guides/integrations-guide/) могут устанавливать свойства и предоставлять функциональность через объект `locals`. Если вы используете интеграцию, ознакомьтесь с ее документацией, чтобы убедиться, что вы не переопределяете ее свойства и не выполняете лишнюю работу.
:::

Внутри `locals` можно хранить любые типы данных: строки, числа и даже сложные типы данных, такие как функции и карты.

```js title="src/middleware.js"
export function onRequest ({ locals, request }, next) {
    // перехват данных из запроса
    // по желанию, измените свойства в `locals`
    locals.user.name = "John Wick";
    locals.welcomeTitle = () => {
        return "Welcome back " + locals.user.name;
    };

    // верните ответ или результат вызова `next()`
    return next();
};
```

Затем вы можете использовать эту информацию внутри любого файла `.astro` с помощью `Astro.locals`.

```astro title="src/pages/orders.astro"
---
const title = Astro.locals.welcomeTitle();
const orders = Array.from(Astro.locals.orders.entries());
---
<h1>{title}</h1>
<p>This {data.property} is from middleware.</p>
<ul>
    {orders.map(order => {
        return <li>{/* do something with each order */}</li>;
    })}
</ul>
```

`locals` - это объект, который живет и умирает в рамках одного маршрута Astro; когда страница вашего маршрута будет отрисована, `locals` перестанет существовать и будет создан новый. Информация, которая должна сохраняться в течение нескольких запросов страницы, должна храниться в другом месте.

:::note
Значение `locals` не может быть переопределено во время выполнения. Это может привести к удалению всей информации, хранящейся пользователем.  В режиме `dev` Astro выполняет проверку и выдает ошибку, если `locals` переопределены.
:::

## Пример: редактирование конфиденциальной информации

В примере ниже используется промежуточное ПО для замены слова "PRIVATE INFO" на слово "REDACTED", что позволяет отображать измененный HTML на вашей странице:

```js title="src/middleware.js"
export const onRequest = async (context, next) => {
    const response = await next();
    const html = await response.text();
    const redactedHtml = html.replaceAll("PRIVATE INFO", "REDACTED");
    
    return new Response(redactedHtml, {
        status: 200,
        headers: response.headers
    });
};
```

## Типы промежуточного ПО

Вы можете импортировать и использовать служебную функцию `defineMiddleware()`, чтобы воспользоваться преимуществами безопасности типов:

```ts
// src/middleware.ts
import { defineMiddleware } from "astro:middleware";

// `context` и `next` автоматически типизируются
export const onRequest = defineMiddleware((context, next) => {

});
```

В противном случае, если вы используете JsDoc для обеспечения безопасности типов, вы можете использовать `MiddlewareHandler`:


```js
// src/middleware.js
/**
 * @type {import("astro").MiddlewareHandler}
 */
// `context` и `next` автоматически типизируются
export const onRequest = (context, next) => {

};
```

Чтобы типизировать информацию внутри `Astro.locals`, что дает вам автозаполнение внутри файлов `.astro` и кода промежуточного программного обеспечения, объявите глобальное пространство имен в файле `env.d.ts`:

```ts title="src/env.d.ts"
/// <reference types="astro/client" />
declare namespace App {
    interface Locals {
        user: {
            name: string
        },
        welcomeTitle: () => string,
        orders: Map<string, object>
    }
}
```

Затем, внутри файла промежуточного ПО, вы можете воспользоваться преимуществами автозавершения и безопасности типов.

## Цепочка промежуточного ПО

Несколько промежуточных программ могут быть объединены в определенном порядке с помощью [`sequence()`](/ru/reference/api-reference/#sequence):

```js title="src/middleware.js"
import { sequence } from "astro:middleware";

async function validation(_, next) {
    console.log("validation request");
    const response = await next();
    console.log("validation response");
    return response;
}

async function auth(_, next) {
    console.log("auth request");
    const response = await next();
    console.log("auth response");
    return response;
}

async function greeting(_, next) {
    console.log("greeting request");
    const response = await next();
    console.log("greeting response");
    return response;
}

export const onRequest = sequence(validation, auth, greeting);
```

Это приведет к следующему порядку в консоли:

```sh
validation request
auth request
greeting request
greeting response
auth response
validation response
```

## Страницы ошибок

Промежуточное ПО будет пытаться запустить все страницы по требованию, даже если подходящий маршрут не может быть найден. Это включает в себя стандартную (пустую) страницу 404 в Astro и любые пользовательские страницы 404. Однако решение о том, будет ли выполняться этот код, зависит от [адаптера](/ru/guides/server-side-rendering/). Некоторые адаптеры могут выдавать вместо этого страницу ошибки, специфичную для конкретной платформы.

Промежуточное ПО также попытается запуститься перед выдачей страницы ошибки 500, включая пользовательскую страницу 500, если только ошибка сервера не произошла во время выполнения самого промежуточного ПО. Если ваше промежуточное ПО не будет успешно запущено, то у вас не будет доступа к `Astro.locals` для отображения вашей 500-страницы.